<?php

/**
 * cwImage - PHP class for general image manipulation (needs cakePHP)
 * Provides basic operations like load, resample, save
 *
 * @author Lucian SABO (luci@criosweb.ro)
 * @copyright 2011 
 */

class cwImage {
    private $_resource;
    private $_imageInfo = array();
    private $_JPEG_options = array (
        'quality' => 85,
        'progressive' => true,
        'grayscale' => false
    );
    
    function __construct($resource = null) {
	if ($resource) {
	    $this->_resource = $resource;
	    $this->_setImageInfo();
	}		
    }
    
    function __destruct() {
	if ($this->_resource) {
	    imagedestroy($this->_resource);
	}
    }
    
    private function _setImageInfo() {
	$this->_imageInfo['width'] = imagesx($this->_resource);
	$this->_imageInfo['height'] = imagesy($this->_resource);	
    }
    
    function load($filename, $headerOnly = false) {
        /*if (! filter_var($url, FILTER_VALIDATE_URL)) {
            throw new Exception(__(sprintf('URL-ul %s nu este valid', $url), true));
        }*/        
	
        if (! file_exists($filename)) {	    
            throw new Exception (__(sprintf("%s does not exist on this server", $filename), true));	    
        }	
	        
	$imageinfo = getimagesize($filename, $additional_info);			
	 
	$this->_imageInfo['width'] = intval($imageinfo[0]);
	$this->_imageInfo['height'] = intval($imageinfo[1]);
	$this->_imageInfo['format'] = intval($imageinfo[2]);	
	$this->_imageInfo['bits'] = intval($imageinfo['bits']);
	if (isset($imageinfo['channels'])) {
	    $this->_imageInfo['channels'] = intval($imageinfo['channels']);
	}
	$this->_imageInfo['mime'] = $imageinfo['mime'];
	$this->_imageInfo['fileName'] = basename($filename);	 
	 
	if ($headerOnly) {
	    return $imageinfo ? true : false;
	}

	switch ($this->_imageInfo['mime']) {
	    case "image/jpeg":
		$this->_resource = ImageCreateFromJPEG($filename);
		break;
	    case "image/png":
		$this->_resource = ImageCreateFromPNG($filename);
		break;
	    case "image/gif":
		$this->_resource = ImageCreateFromGIF($filename);
		break;
	    default:
		throw new Exception(__(sprintf('Unknown image type %d', $this->_imageInfo['mime']), true));
	}		
        
        if (! $this->_resource) {	    
            throw new Exception(__("The image is not valid", true));	    
        }
	
	$this->_setImageInfo();
        
        return $this->_resource ? true : false;
    }
    
    /**
     * Resize and crop the current image
     * @param mixed $crop currently not used - set to null - aspect ratio for cropping can be given as array (4,3) or as string "4:3"
     * @param mixed $size new size can be given as array (200,300) or as string "200x300" or simply "x300" for height
     * @param array options. Available options:
     * $defaultOptions = array (
     *    'exactSize' => true,
     *    'resizeSmaller' => true
     * );
     * @return cwImage resized image or false on error
     */
    function resize($crop = null, $size = null, $options = array()) {
	
	if (is_resource($this->_resource) === false) {
	    throw new Exception(__("crop/resize error: No image loaded", true));
	}
	
	$x = 0;
	$y = 0;
	$xOffset = 0;
	$yOffset = 0;
	$width = $this->_imageInfo['width'];
	$height = $this->_imageInfo['height'];	
	
	$defaultOptions = array (
	    'exactSize' => true,
	    'resizeSmaller' => true
	);
	
	$options = array_merge($defaultOptions, $options);

	/*
	CROP (Aspect Ratio) Section
	 * CURRENTLY NOT WORKING PROPERLY !
	*/

	if (is_null($crop) === true) {
	   $crop = array('wide' => $this->_imageInfo['width'], 'tall' => $this->_imageInfo['height']);
	} else {
	    // if the user passed the crop param as string Ex: "4:3"
	    if (!is_array($crop)) {
		$cropInfo = array_filter(explode(':', $crop));
		$crop = array('wide' => $cropInfo[0], 'tall' => $cropInfo[1]);
	    }

	   if (empty($crop) === true) {
		   $crop = array('wide' => $this->_imageInfo['width'], 'tall' => $this->_imageInfo['height']);
	   } else {
	       if ((empty($crop['wide']) === true) || (is_numeric($crop['wide']) === false)) {
		       $crop['wide'] = $crop['tall'];
	       } else if ((empty($crop['tall']) === true) || (is_numeric($crop['tall']) === false)) {
		       $crop['tall'] = $crop['wide'];
	       }
	   }	  
	}
	
	$ratio = array(0 => $this->_imageInfo['width'] / $this->_imageInfo['height'], 1 => $crop['wide'] / $crop['tall']);

       /*if ($ratio[0] > $ratio[1]) {
	   $width = round($this->_imageInfo['height'] * $ratio[1]);
	   $x = ($this->_imageInfo['width'] - $this->_imageInfo['width']) / 2;	       
       }

       else if ($ratio[0] < $ratio[1]) {
	   $height = round($this->_imageInfo['width'] / $ratio[1]);
	   $y = ($this->_imageInfo['height'] - $this->_imageInfo['height']) / 2;
       }	   */	

	/*
	Resize Section
	*/

	if (is_null($size) === true) {
	   $size = array('width' => $this->_imageInfo['width'], 'height' => $this->_imageInfo['height']);
	}

	else {
	    // if the user passed the crop param as string Ex: "200x300" or "x200"
	    if (!is_array($size)) { 
		$sizeInfo = array_filter(explode('x', $size));
		$size = array('width' => $sizeInfo[0], 'height' => $sizeInfo[1]);
	    }

	   if (empty($size) === true) {
		   $size = array('width' => imagesx($this->_resource), 'height' => imagesy($this->_resource));
	   } else {
	       if (((empty($size['width']) === true) || (is_numeric($size['width']) === false)) || ((empty($size['height']) === true) || (is_numeric($size['height']) === false))) {
		   if ((empty($size['width']) === true) || (is_numeric($size['width']) === false)) {
			   $size['width'] = round($size['height'] * $this->_imageInfo['width'] / $this->_imageInfo['height']);
		   } else if ((empty($size['height']) === true) || (is_numeric($size['height']) === false)) {
			   $size['height'] = round($size['width'] * $this->_imageInfo['height'] / $this->_imageInfo['width']);
		   }
		   
		   $boxWidth = $size['width'];
		   $boxHeight = $size['height'];
	       } else {
		   $targetRatio = $size['width'] / $size['height'];
		   $boxWidth = $size['width'];
		   $boxHeight = $size['height'];
		   
		    if ($ratio[0] > $targetRatio){
			$size['width'] = $boxWidth;
			$size['height'] = round($boxWidth / $ratio[0]);
			$xOffset = 0;
			$yOffset = round(($boxHeight - $size['height']) / 2);
		    } else {
			$size['height'] = $boxHeight;
			$size['width'] = round($boxHeight * $ratio[0]);			
			$xOffset = round(($boxWidth - $size['width']) / 2);
			$yOffset = 0;
		    }		   
	       }
	   }
	}

	if (! $options['resizeSmaller'] && ($width <= $size['width'] &&  $height <= $size['height'])) {
	    $insert = ImageCreateTrueColor($width, $height);	
	} else {
	    $insert = ImageCreateTrueColor($size['width'], $size['height']);	
	}
	
	ImageFill($insert, 0, 0, ImageColorAllocate($insert, 255, 255, 255));
	  
	if (is_resource($insert) === true) {
	    
	    ImageSaveAlpha($insert, true);
	    ImageAlphaBlending($insert, true);	    	   
	    
	    if (! $options['resizeSmaller'] && ($width <= $size['width'] &&  $height <= $size['height'])) {
		ImageCopy($insert, $this->_resource, 0, 0, $x, $y, $width, $height);
	    } else {
		ImageCopyResampled($insert, $this->_resource, 0, 0, $x, $y, $size['width'], $size['height'], $width, $height);
	    }

	    if (! $options['exactSize']) {
		return new cwImage($insert);
	    }
	   
	    $result = ImageCreateTrueColor($boxWidth, $boxHeight);
	    ImageFill($result, 0, 0, ImageColorAllocate($result, 255, 255, 255));

	    if (is_resource($result) === true) {
		ImageCopyMerge($result, $insert, $xOffset, $yOffset, 0, 0, $size['width'], $size['height'], 100);
		return new cwImage($result);	  
	    }
	    
	} else {
	    return false;
	}
        
    }
    
    function save($filename = null, $imageType = IMG_JPG, $params = null) {
        
        switch ($imageType) {
            case IMG_JPG:
                $this->setJPEGOptions($params);
		if (is_null($filename)) {
		    // Set the content type header - in this case image/jpeg
		    header('Content-type: image/jpeg');
		}
		
		return ImageJPEG($this->_resource, $filename, $this->_JPEG_options['quality']);
		break;
            default:
                throw new Exception(__(sprintf('Unknown output type %d', $imageType), true));
        }
    	        
    }
    
    function setDefaultJPEGOptions() {
	$this->_JPEG_options = array (
	    'quality' => 85,
	    'progressive' => true,
	    'grayscale' => false
	);	
    }
    
    function setJPEGOptions($params) {
	if (! empty ($params)) {
	     $this->_JPEG_options = $params;
	} else {
	    $this->setDefaultJPEGOptions();
	}

	if ($this->_JPEG_options['progressive']) {
	    imageinterlace($this->_resource, 1);
	} else {
	    imageinterlace($this->_resource, 0);
	}
    }
    
    function sendToBrowser($imageType = IMG_JPG, $params = null) {
	$this->save(null, $imageType, $params);
    }
    
    function getInfo() {
	return $this->_imageInfo;
    }
    
    function getWidth() {
	return $this->_imageInfo['width'];
    }
    
    function getHeight() {
	return $this->_imageInfo['height'];
    }
    
    
    /**
     * Changes the filename extension     
     * 
     * @param string $filename
     * @param string $newExtension The new extension must include the dot sign
     * To remove extension simply call this function without the $newExtension parameters
     * @return string new filename 
     */
    function changeExtension($filename, $newExtension = '') {
	return preg_replace('/\..+$/', $newExtension, $filename);
    }
    
    /**
     * Cleanup filename of bizare characters
     * 
     * @return string cleaned version of filename 
     */
    function cleanFileName() {
	return Inflector::slug($this->changeExtension($this->_imageInfo['fileName']));
    }
    
}
?>
